<?php

namespace App\Services;

use App\Models\MasterAccess;
use App\Models\MasterPermission;
use App\Models\MasterUser;
use App\Models\MasterUserRole;
use App\Models\MasterMenu;
use common\enum\CommonEnum;
use common\enum\MasterLogEnum;
use common\utils\SysCode;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class RoleService
{
    public static function roleAuthList($param)
    {
        $user = Auth::user();
        $operateRoleId = $user['role'];                                     //操作者
        $userRoleId = empty($param['role']) ? 0 : (int)$param['role'];       //被操作人
        $res = [];
        $menuSel = "id,level,parent,name,url";
        $accessSel = "id,pid,menu_id as parent,name,method,api as url";
        $menu = MasterMenu::selectRaw($menuSel)->orderBy('order', 'asc')->get()->toArray();
        $access = MasterAccess::selectRaw($accessSel)->get()->toArray();
        $userMenuIds = $userAccessIds = $operateMenuIds = $operateAccessIds = [];
        self::getAuths($operateRoleId,$operateMenuIds,$operateAccessIds);
        if ($userRoleId) {
            //获取角色信息
            $res['role'] = MasterUserRole::where(['id' => $userRoleId])->value('role');
            if (!$res['role']) {
                error_exit(SysCode::ROLE_NOT_EXIST);
            }
            //菜单和权限获取
            self::getAuths($userRoleId, $userMenuIds, $userAccessIds);
        }
        if ($operateRoleId != CommonEnum::ADMIN_ROLE_ID) {
            self::filterAuth($operateMenuIds, $userMenuIds);
            self::filterAuth($operateAccessIds, $userAccessIds);
        }
        //将菜单和权限转化为一个树状结构
        foreach ($access as &$acc) {
            $acc['type'] = 'access';
        }
        $accessTree = AccessService::listToTree($access,0);
        $menusIds = array_column($menu, 'id');
        $menus = array_combine($menusIds, $menu);
        foreach ($accessTree as $acc) {
            if (!empty($menus[$acc['parent']])) {
                $menus[$acc['parent']]['children'][] = $acc;
            }
        }
        $menus = array_values($menus);
        foreach ($menus as &$menu) {
            $menu['type'] = 'menu';
        }
        AccessService::listToTree($menus,0,'parent','id');
        $levels = [];
        foreach ($menus as $menuItem) {
            if (in_array($menuItem['id'],$operateMenuIds)){
                $menuItem['type'] = 'menu';
                $levels[$menuItem['level']][$menuItem['id']] = $menuItem;
            }
        }
        $length = count($levels);
        for ($i = $length; $i > 1; $i--) {
            foreach ($levels[$i] as $id => &$menu) {
                if (!empty($levels[$i - 1][$menu['parent']])) {
                    $levels[$i - 1][$menu['parent']]['children'][] = $menu;
                }
            }
        }
        $tree = [];
        if (!empty($levels)) {
            $tree = array_values($levels[1]);
        }
        foreach ($tree as &$leaf) {
            self::addColumn($leaf, $userMenuIds, $userAccessIds);
        }
        $res['routes'] = $tree;
        self::nullToStr($res);
        return $res;
    }

    public static function roleList($page = 1, $pageSize = 20)
    {
        $select = [
            'a.id',
            'a.role',
            'a.num',
            'a.updated_at as update_time',
            'b.username as operator'
        ];
        $model = new MasterUserRole();
        $tableName = $model->getTable();
        $query = $model->from($tableName . " as a")
            ->select($select)
            ->leftJoin("master_user as b", 'a.operator', '=', 'b.id');
        $operator = Auth::user();
        $operatorId = $operator['id'];
        $operatorRoleId = $operator['role'];
        if ($operatorRoleId !== CommonEnum::ADMIN_ROLE_ID){
            $query->where('a.id',$operatorRoleId);
            $query->orWhere('a.creator',$operatorId);
        }
        return get_page_data($query, $page, $pageSize);
    }

    public static function editRoleAuth($param)
    {
        $data = [];
        if (!empty($param['id'])) {
            //编辑角色权限写入日志
            $roleData = self::roleAuthList(['role'=>$param['id']]);
            $data['old'] = ['role' => $roleData['role'], 'auth' => $roleData['routes']];
        }
        $user = Auth::user();
        $operateId = $user->id;
        $operateRoleId = $user->role;
        $role = $param['role'];
        $auth = $param['auth'];
        $adminUserRoleModel = new MasterUserRole();
        $adminPermissionModel = new MasterPermission();

        //获得操作者和被操作者的菜单id和权限id,过滤被操作者的菜单和权限
        $operateMenuIds = $operateAccessIds = $userMenuIds = $userAccessIds = $userHasMenuIds = $userHasAccessIds = [];
        self::getAuthIds($auth, $userMenuIds, $userAccessIds);
        self::getAuths($operateRoleId, $operateMenuIds, $operateAccessIds);
        if ($operateRoleId != CommonEnum::ADMIN_ROLE_ID) {
            self::filterAuth($operateMenuIds, $userMenuIds);
            self::filterAuth($operateAccessIds, $userAccessIds);
        }
        //编辑用户时,取出角色有的,但操作者没有的,这些权限无法修改
        if (!empty($param['id']) && $operateRoleId != CommonEnum::ADMIN_ROLE_ID){
            self::getAuths($param['id'],$userHasMenuIds,$userHasAccessIds);
            self::getExtraAuth($operateMenuIds,$userHasMenuIds);
            self::getExtraAuth($operateAccessIds,$userHasAccessIds);
        }
        $userMenuIds = array_merge($userMenuIds,$userHasMenuIds);
        $userAccessIds = array_merge($userAccessIds,$userHasAccessIds);
        DB::beginTransaction();
        try {
            //存入master_user_role表
            $adminUserRoleSaveData = [
                'role' => $role,
                'operator' => $operateId,
            ];
            if (empty($param['id'])) {
                $adminUserRes = $adminUserRoleModel->where('role', '=', $role)->first();
                if ($adminUserRes) {
                    error_exit(SysCode::ROLE_ALREADY_EXIST);
                }
                $adminUserRoleSaveData['creator'] = $operateId;
                $role_id = $adminUserRoleModel->insertGetId($adminUserRoleSaveData);
            } else {
                $role_id = $param['id'];
                if ($role_id == $operateRoleId){
                    error_exit(SysCode::INVALID_ARGUMENT);
                }
                if ($role_id == CommonEnum::ADMIN_ROLE_ID) {
                    error_exit(SysCode::USER_AUTH_NOT_MATCH);
                }
                $userRole = $adminUserRoleModel->where(['id' => $role_id])->first();
                if (!$userRole) {
                    error_exit(SysCode::ROLE_NOT_EXIST);
                }
                $adminUserRoleModel->where(['id' => $role_id])->update($adminUserRoleSaveData);
            }
            //存入admin_permission表
            $adminPermissionModel->where('role_id', '=', $role_id)->delete();
            $access = MasterAccess::select(['menu_id','id'])->get()->toArray();
            $id = array_column($access,'id');
            $access = array_combine($id,$access);
            $adminPermissionSaveData = [];
            foreach ($userMenuIds as $userMenuId) {
                $permission['role_id'] = $role_id;
                $permission['menu_id'] = $userMenuId;
                $permission['access_id'] = 0;
                $adminPermissionSaveData[] = $permission;
            }
            foreach ($userAccessIds as $userAccessId) {
                $menuId = $access[$userAccessId]['menu_id'];
                $permission['role_id'] = $role_id;
                $permission['menu_id'] = $menuId;
                $permission['access_id'] = $userAccessId;
                $adminPermissionSaveData[] = $permission;
            }
            if (!empty($adminPermissionSaveData)) {
                $adminPermissionModel->insert($adminPermissionSaveData);
            }
            $adminIds = MasterUser::where(['role'=>$role_id])->pluck('id')->toArray();
            AdminService::kickAdminOut($adminIds);
            DB::commit();
        } catch (Exception $e) {
            error_exit($e->getMessage());
            DB::rollBack();
        }
        if (!empty($param['id'])) {
            //编辑角色权限写入日志
            $data['new'] = ['role' => $param['role'], 'auth' => $param['auth']];
            $remark       = str_replace('{:name}', $param['role'], MasterLogEnum::REMARK['role_edit']);
            MasterLogService::writeMasterLog(MasterLogEnum::ROLE_EDIT, MasterLogEnum::SUCCESS, $remark, $data);
        } else {
            //新增角色权限写入日志
            $data['new'] = ['role' => $param['role'], 'auth' => $param['auth']];
            $remark      = str_replace('{:name}', $param['role'], MasterLogEnum::REMARK['role_add']);
            MasterLogService::writeMasterLog(MasterLogEnum::ROLE_ADD, MasterLogEnum::SUCCESS, $remark, $data);
        }
        return [];
    }

    /**
     * 写入日志格式化数据
     * @param $rloeArry
     * @return array
     */
//    public static function dataChange(&$data)
//    {
//        foreach ($data as &$datum) {
//            if (!empty($datum['id'])) {
//                unset($datum['id']);
//            }
//            if (!empty($datum['level'])) {
//                unset($datum['level']);
//            }
//            if (!empty($datum['parent']) || isset($datum['parent'])) {
//                unset($datum['parent']);
//            }
//            if (!empty($datum['url']) || isset($datum['url'])) {
//                unset($datum['url']);
//            }
//            if (!empty($datum['type'])) {
//                unset($datum['type']);
//            }
//            if (!empty($datum['method'])) {
//                unset($datum['method']);
//            }
//            if (!empty($datum['children']) && is_array($datum['children'])) {
//                self::dataChange($datum['children']);
//            }
//        }
//        return $data;
//    }


    public static function delRole($param)
    {
        /****************写入日志获取原有角色权限**************/
        $roleArray         = [];
        $roleArray['role'] = $param['id'];
        $roleData     = self::roleAuthList($roleArray);
        /****************END**************/
        $roleId = $param['id'];
        $operator = Auth::user();
        if ($roleId = $operator['role']){
            error_exit(SysCode::INVALID_ARGUMENT);
        }
        $adminUserRoleModel = new MasterUserRole();
        $adminPermissionModel = new MasterPermission();
        $role = $adminUserRoleModel->where('id', '=', $roleId)->first();

        if (!$role) {
            error_exit(SysCode::ROLE_NOT_EXIST);
        }
        if ($role['num']){
            error_exit(SysCode::ROLE_IN_USE);
        }
        DB::beginTransaction();
        try {
            $adminUserRoleModel->where(['id' => $roleId])->delete();
            $adminPermissionModel->where(['role_id' => $roleId])->delete();
            DB::commit();
        } catch (Exception $e) {
            error_exit($e->getMessage());
            DB::rollBack();
        }
        /****************START**************/
        $data['new'] = ['role' => $roleData['role'], 'auth' => $roleData['routes']];
        $remark = str_replace('{:name}',$role['role'], MasterLogEnum::REMARK['role_del']);
        MasterLogService::writeMasterLog(MasterLogEnum::ROLE_DEL, MasterLogEnum::SUCCESS, $remark,$data);
        /****************END**************/
        return [];
    }

    //获得该角色有的菜单和权限
    public static function getAuths($roleId, &$menuIds, &$accessIds)
    {
        if ($roleId == CommonEnum::ADMIN_ROLE_ID){
            $menu = MasterMenu::select('id')->get()->toArray();
            $access = MasterAccess::select('id')->get()->toArray();
            $menuIds = array_column($menu, 'id');
            $accessIds = array_column($access,'id');
            return true;
        }
        $where = ['role_id' => $roleId];
        $permissions = MasterPermission::select(['menu_id', 'access_id'])->where($where)->get()->toArray();
        foreach ($permissions as $permission) {
            if ($permission['access_id']) {
                $accessIds[] = $permission['access_id'];
            } else {
                $menuIds[] = $permission['menu_id'];
            }
        }
    }

    //通过参数获得选中的菜单和权限
    public static function getAuthIds($auth, &$menuIds, &$accessIds)
    {
        foreach ($auth as $item) {
            if (!empty($item['model']) || !empty($item['indeterminate'])) {
                if ($item['type'] == 'menu') {
                    $menuIds[] = $item['id'];
                } elseif ($item['type'] == 'access') {
                    $accessIds[] = $item['id'];
                }
            }
            if (!empty($item['children'])) {
                self::getAuthIds($item['children'], $menuIds, $accessIds);
            }
        }
    }

    //给子元素添加2列参数
    private static function addColumn(&$leaf, $menuIds, $accessIds)
    {
        $leaf['model'] = false;
        if (empty($leaf['children'])) {
            if (in_array($leaf['id'], $menuIds) && $leaf['type'] == 'menu') {
                $leaf['model'] = true;
            }
            if (in_array($leaf['id'], $accessIds) && $leaf['type'] == 'access') {
                $leaf['model'] = true;
            }
        }
        if (!empty($leaf['children']) && is_array($leaf['children'])) {
            $leaf['indeterminate'] = false;
            $selected = 0;
            $count = count($leaf['children']);
            foreach ($leaf['children'] as &$child) {
                if ((in_array($child['id'], $menuIds) && $child['type'] == 'menu') || (in_array($child['id'], $accessIds) && $child['type'] == 'access')) {
//                    echo $child['id']." ".$child['type'];
                    $selected += 1;
                }
                self::addColumn($child, $menuIds, $accessIds);
            }
            if ((!empty($menuIds) || !empty($accessIds)) && $selected) {
                $leaf['indeterminate'] = $selected < $count ? true : false;
            }
            $leaf['model'] = $selected == $count ? true : false;
            if (!$selected) {
                $leaf['model'] = false;
                if (!empty($menuIds) && $leaf['type'] == "menu" && in_array($leaf['id'], $menuIds)) {
                    $leaf['model'] = true;
                }
                if (!empty($accessIds) && $leaf['type'] == "access" && in_array($leaf['id'], $accessIds)) {
                    $leaf['model'] = true;
                }
            }

        }
    }

    //获取子元素授权记录
    private static function getChildAuth($auth, &$authIds)
    {
        foreach ($auth as $value) {
            if (!empty($value['model']) || !empty($value['indeterminate'])) {
                $authIds[] = $value['id'];
            }
            if (!empty($value['children']) && is_array($value['children'])) {
                self::getChildAuth($value['children'], $authIds);
            }
        }
    }

    //过滤参数
    public static function filterAuth($operateAuth,&$userAuth)
    {
        foreach ($userAuth as $key => $authId) {
            if (!in_array($authId,$operateAuth)){
                unset($userAuth[$key]);
            }
        }
    }

    //为空字段转为str类型
    private static function nullToStr(&$array)
    {
        if (is_array($array)) {
            foreach ($array as &$value) {
                if (is_array($value)) {
                    self::nullToStr($value);
                }
                if ($value === null) {
                    $value = '';
                }
            }
        }
    }

    //获取操作者没有的权限
    public static function getExtraAuth($operateAuth,&$userAuth)
    {
        foreach ($userAuth as $key => $authId) {
            if (in_array($authId,$operateAuth)){
                unset($userAuth[$key]);
            }
        }
    }
}